use std::io::{self, Stdout};
use std::ptr;
use std::os::raw::c_int;

use ratatui::{
    backend::CrosstermBackend,
    Terminal,
};
use crossterm::{
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};

use crate::{RatatuiResult, RatatuiWidget};

/// Opaque terminal handle for FFI
#[repr(C)]
pub struct RatatuiTerminal {
    terminal: Terminal<CrosstermBackend<Stdout>>,
    widgets: Vec<*mut RatatuiWidget>,
}

impl RatatuiTerminal {
    fn new() -> Result<Self, Box<dyn std::error::Error>> {
        enable_raw_mode()?;
        let mut stdout = io::stdout();
        execute!(stdout, EnterAlternateScreen)?;
        let backend = CrosstermBackend::new(stdout);
        let terminal = Terminal::new(backend)?;
        
        Ok(RatatuiTerminal {
            terminal,
            widgets: Vec::new(),
        })
    }

    fn cleanup(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        disable_raw_mode()?;
        execute!(
            self.terminal.backend_mut(),
            LeaveAlternateScreen
        )?;
        self.terminal.show_cursor()?;
        Ok(())
    }

    fn draw(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        self.terminal.draw(|f| {
            // For now, just clear the screen
            // In the future, this will render the widgets
            let area = f.area();
            f.render_widget(ratatui::widgets::Clear, area);
            
            // Render any added widgets
            for widget_ptr in &self.widgets {
                if !widget_ptr.is_null() {
                    unsafe {
                        let widget = &**widget_ptr;
                        widget.render(f, area);
                    }
                }
            }
        })?;
        Ok(())
    }

    fn add_widget(&mut self, widget: *mut RatatuiWidget) {
        if !widget.is_null() {
            self.widgets.push(widget);
        }
    }

    fn clear_widgets(&mut self) {
        self.widgets.clear();
    }
}

/// Create a new terminal instance
#[no_mangle]
pub extern "C" fn ratatui_terminal_new() -> *mut RatatuiTerminal {
    match RatatuiTerminal::new() {
        Ok(terminal) => Box::into_raw(Box::new(terminal)),
        Err(_) => ptr::null_mut(),
    }
}

/// Free a terminal instance
#[no_mangle]
pub extern "C" fn ratatui_terminal_free(terminal: *mut RatatuiTerminal) {
    if !terminal.is_null() {
        unsafe {
            let mut terminal = Box::from_raw(terminal);
            let _ = terminal.cleanup();
        }
    }
}

/// Draw the terminal
#[no_mangle]
pub extern "C" fn ratatui_terminal_draw(terminal: *mut RatatuiTerminal) -> c_int {
    if terminal.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let terminal = &mut *terminal;
        match terminal.draw() {
            Ok(_) => RatatuiResult::Ok as c_int,
            Err(_) => RatatuiResult::ErrorTerminalDraw as c_int,
        }
    }
}

/// Add a widget to the terminal
#[no_mangle]
pub extern "C" fn ratatui_terminal_add_widget(
    terminal: *mut RatatuiTerminal,
    widget: *mut RatatuiWidget,
) -> c_int {
    if terminal.is_null() || widget.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let terminal = &mut *terminal;
        terminal.add_widget(widget);
        RatatuiResult::Ok as c_int
    }
}

/// Clear all widgets from the terminal
#[no_mangle]
pub extern "C" fn ratatui_terminal_clear_widgets(terminal: *mut RatatuiTerminal) -> c_int {
    if terminal.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let terminal = &mut *terminal;
        terminal.clear_widgets();
        RatatuiResult::Ok as c_int
    }
}

/// Get terminal size
#[no_mangle]
pub extern "C" fn ratatui_terminal_size(
    terminal: *mut RatatuiTerminal,
    width: *mut u16,
    height: *mut u16,
) -> c_int {
    if terminal.is_null() || width.is_null() || height.is_null() {
        return RatatuiResult::ErrorNullPointer as c_int;
    }

    unsafe {
        let terminal = &*terminal;
        let size = terminal.terminal.size().unwrap_or_default();
        *width = size.width;
        *height = size.height;
        RatatuiResult::Ok as c_int
    }
}
